﻿using EntityframeworkHelper.Data.Configurations;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Reflection;

// ReSharper disable StaticMemberInGenericType

namespace EntityFrameworkHelper.Migrations
{
    /// <summary>
    ///     Class DatabaseInitializer.
    /// </summary>
    /// <typeparam name="TContext">The type of the t context.</typeparam>
    public class DatabaseInitializer<TContext> where TContext : DbContext, new()
    {
        /// <summary>
        ///     The mapper assemblies
        /// </summary>
        private static readonly ICollection<Assembly> MapperAssemblies;

        /// <summary>
        ///     Initializes static members of the <see cref="DatabaseInitializer{TContext}" /> class.
        /// </summary>
        static DatabaseInitializer()
        {
            MapperAssemblies = new List<Assembly>();
        }

        /// <summary>
        ///     获取 数据实体映射配置信息集合
        /// </summary>
        /// <value>The entity mappers.</value>
        public static ICollection<IEntityMapper> EntityMappers
        {
            get { return GetAllEntityMapper(); }
        }

        /// <summary>
        ///     添加需要搜索实体映射的程序集到检索集合中
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        public static void AddMapperAssembly(Assembly assembly)
        {
            if (MapperAssemblies.Any(m => m == assembly))
            {
                return;
            }
            MapperAssemblies.Add(assembly);
        }

        /// <summary>
        ///     设置数据库初始化，策略为自动迁移到最新版本
        /// </summary>
        public static void Initialize()
        {
            TContext context = new TContext();
            if (!context.Database.Exists())
            {
                Database.SetInitializer(new CreateDatabaseIfNotExistsWithSeed<TContext>());
            }
            else
            {
                Database.SetInitializer(new MigrateDatabaseToLatestVersion<TContext, MigrationsConfiguration<TContext>>());
            }

            ////EF预热，解决EF6第一次加载慢的问题
            ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
            StorageMappingItemCollection mappingItemCollection = (StorageMappingItemCollection)objectContext.ObjectStateManager
                .MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
            mappingItemCollection.GenerateViews(new List<EdmSchemaError>());
            context.Dispose();
        }

        /// <summary>
        ///     Gets all entity mapper.
        /// </summary>
        /// <returns>ICollection&lt;IEntityMapper&gt;.</returns>
        private static ICollection<IEntityMapper> GetAllEntityMapper()
        {
            Type baseType = typeof(IEntityMapper);
            Type[] mapperTypes = MapperAssemblies.SelectMany(assembly => assembly.GetTypes())
                .Where(type => baseType.IsAssignableFrom(type) && type != baseType && !type.IsAbstract).ToArray();
            ICollection<IEntityMapper> result = mapperTypes.Select(type => Activator.CreateInstance(type) as IEntityMapper).ToList();
            return result;
        }
    }
}